/*
	msgMBoxCreate() causes EVENT_MSGQCREATE
	msgMBoxDestroy() causes EVENT_MSGQDELETE
	msgMBoxSend() causes EVENT_MSGQSEND
	msgMBoxReceive() causes EVENT_MSGQRECEIVE
*/

#include "vxWorks.h"
#include "stdlib.h"
#include "string.h"
#include "taskLib.h"
#include "smObjLib.h"
#include "errnoLib.h"
#include "intLib.h"
#include "eventLib.h"
#include "unistd.h"
#include "time.h"
#include "stdio.h"
#include "objLib.h"

typedef int s32;
typedef unsigned int u32;
typedef unsigned char u8;

typedef struct mailBox
{
    SEM_ID id;
    u8 *msg; 
}msgMBox_t;

enum EmsgMBox
{
    EMSGMBOX_NOT_ISR_CALLENABLE=1,
    EMSGMBOX_TIMEOUT,
    EMSGMBOX_ID_ERR, 
    EMSGMBOX_UNAVAILABLE,
    EMSGMBOX_INVALID_OPERATION,
    EMSGMBOX_EVENTSEND_FAILED,
    EMSGMBOX_NO_OBJECT_DESTROY,
};

enum msgMBoxState
{
    msgMBoxEmpty=0x0,
    msgMBoxFull,
};

enum msgMBoxStyle
{
    msgMBoxFIFO=0x0,
    msgMBoxPRIORITY,
};

#define sleep(timeO) taskDelay (timeO * (sysClkRateGet())) /* macro */

/*
*********************************************************************************************************
*                                         CREATE A MAIBOX
*
* Description: This function deletes a mailbox and readies all tasks pending on the mailbox.
*
* Arguments  : options     The <options> parameter specifies the queuing style for blocked tasks.
*                          Tasks can be queued on a priority basis or a first-in-first-out basis.
*                          These options are msgMBoxPRIORITY (0x1) and msgMBoxFIFO (0x0), respectively
*
*              MboxState     The initialized to the <MboxState> of either msgMBoxFull (1) or msgMBoxEmpty (0).
*
*
* Returns    : The msgMBox_t struct, or NULL if memory cannot be allocated.
*
* ERRNO      : EMSGMBOX_NOT_ISR_CALLENABLE, EMSGMBOX_INVALID_OPERATION, EMSGMBOX_ID_ERR, EMSGMBOX_EVENTSEND_FAILED
*
* Note(s)    : 
*                
*********************************************************************************************************
*/

msgMBox_t *msgMBoxCreate(u8 options, u8 mBoxState)
{

   msgMBox_t *msg_Mbox;
   msg_Mbox = (msgMBox_t *)calloc(1, sizeof(msgMBox_t));
   if(NULL == msg_Mbox)
   {
        printf("msgMbox calloc failed\n");
        return NULL;
   }     
   msg_Mbox->id = semBCreate(options, mBoxState);
   msg_Mbox->msg == NULL;
   if(NULL == msg_Mbox->id)
   {    
        printf("msgMbox's semBCreate failed\n");
        return NULL;
   }     
    return msg_Mbox;  
}
/*
*********************************************************************************************************
*                                         DELETE A MAIBOX
*
* Description: This function deletes a mailbox and readies all tasks pending on the mailbox.
*
* Arguments  : msgMBox     is a pointer to the message associated with the desired mailbox.
**
*
* Returns    : OK, or ERROR if the mailbox ID is invalid
*
* ERRNO      : EMSGMBOX_NOT_ISR_CALLENABLE, EMSGMBOX_ID_ERR, EMSGMBOX_NO_OBJECT_DESTROY
*
* Note(s)    : 
*                
*********************************************************************************************************
*/


STATUS msgMBoxDelete(msgMBox_t *msgMBox)
{
    u32 err =0;
    if(NULL == msgMBox->id)
          return err;

   err = semDelete(msgMBox->id);
   switch(err)
   {
        case S_intLib_NOT_ISR_CALLABLE:
            err = EMSGMBOX_NOT_ISR_CALLENABLE;
            break;
        case S_objLib_OBJ_ID_ERROR:
            err = EMSGMBOX_ID_ERR;
            break;
        case S_smObjLib_NO_OBJECT_DESTROY:
            err = EMSGMBOX_NO_OBJECT_DESTROY;
            break;
        default:
            printf("msgMboxDel err %d\n",err);
            break;
   }
   cfree((char *)msgMBox); 
   return err;
}

/*
*********************************************************************************************************
*                                         SEND A MAIBOX
*
* Description: This function deletes a mailbox and readies all tasks pending on the mailbox.
*
* Arguments  : msgMBox     is a pointer to the message associated with the desired mailbox.
*
*              msg           the message that wanted to send
*
*
* Returns    : OK, or ERROR if the mailbox ID is invalid
*
* ERRNO      : EMSGMBOX_NOT_ISR_CALLENABLE, EMSGMBOX_INVALID_OPERATION, EMSGMBOX_ID_ERR, EMSGMBOX_EVENTSEND_FAILED
*
* Note(s)    : 
*                
*********************************************************************************************************
*/

STATUS msgMBoxSend(msgMBox_t *msgMBox, u8 *msg)
{
    u32 err=0;
    if(NULL == msgMBox->id)  
      return EMSGMBOX_ID_ERR;
    err = semGive(msgMBox->id);
    switch(err)
    {
        case OK:
            msgMBox->msg = msg;
            break;
        case S_intLib_NOT_ISR_CALLABLE:
            err = EMSGMBOX_NOT_ISR_CALLENABLE;
            break;
        case S_objLib_OBJ_ID_ERROR:
            err = EMSGMBOX_ID_ERR;
            break;
        case S_semLib_INVALID_OPERATION:
            err = EMSGMBOX_INVALID_OPERATION;
            break;
        case S_eventLib_EVENTSEND_FAILED:
            err = EMSGMBOX_EVENTSEND_FAILED;
            break;
        default:
            printf("msgMBoxSend err %d\n",err);
            break;
    }
    return err;
}

/*
*********************************************************************************************************
*                                         RECEVIE A MAIBOX
*
* Description: This function deletes a mailbox and readies all tasks pending on the mailbox.
*
* Arguments  : msgMBoxId     is a pointer to the message associated with the desired mailbox.
*
*              msg           the message that wanted to send
*
*              timeout       If a task times out, msgMBoxReceive() will return ERROR, 
*                            Timeouts of WAIT_FOREVER (-1) and NO_WAIT (0) indicate to wait
*                            indefinitely or not to wait at all.
*
* Returns    : OK, or ERROR if the mailbox ID is invalid or the task timed out.
*
* ERRNO      : EMSGMBOX_NOT_ISR_CALLENABLE, EMSGMBOX_TIMEOUT, EMSGMBOX_ID_ERR, EMSGMBOX_UNAVAILABLE
*
* Note(s)    : 
*                
*********************************************************************************************************
*/
u8 *msgMBoxReceive(msgMBox_t *msgMBox, /* mailbox object to take */
                            u32 timeout,         /* timeout in ticks */
                            u32 *err             /* pointer to the err val*/  
                            )         
{
    u32 sem_ret=0;
    u8 *msg = NULL;
    
    SEM_ID id;
    if( NULL == msgMBox->id)
        *err = EMSGMBOX_ID_ERR;  

    sem_ret = semTake(msgMBox->id,timeout);
    switch(sem_ret)
    {   
        case OK:
            msg = msgMBox->msg;
            break;
        case S_intLib_NOT_ISR_CALLABLE:
            *err = EMSGMBOX_NOT_ISR_CALLENABLE;
            break;    
        case S_objLib_OBJ_TIMEOUT:
            *err = EMSGMBOX_TIMEOUT;
            break;
        case S_objLib_OBJ_ID_ERROR:
            *err = EMSGMBOX_ID_ERR;
            break;
        case S_objLib_OBJ_UNAVAILABLE:
            *err = EMSGMBOX_UNAVAILABLE;
            break;
        default:
            printf("msgMBoxRecv err %d\n",*err);
            break;
     }       
     return msg;
}


msgMBox_t *mBox;
#define STK_SIZE 20000  
#define SEND_PRORITY 100
#define RECV_PRORITY 200
#define OPTIONS 0


#define STR 1
void task_send(void)
{
    u8 message[]="welcome mailbox";
    u8 value=30;
    while(1)
    {
#if STR    
    msgMBoxSend(mBox, message);
    printf("send %s\n", message);
#else    
    msgMBoxSend(mBox, &value);
    printf("send %d\n", value);
#endif    
    sleep(8);
    }
}

void task_recv(void)
{
    u8 *recv=NULL;
    u32 err=0;
    while(1)
    {
     recv = msgMBoxReceive(mBox, 2, &err);
     if(err != OK)
     {
        printf("task recv err %d\n", err);
     }
#if STR       
    printf("recv %s\n", recv);
#else
    printf("recv %d\n", *recv);
#endif
    
    sleep(3);
    }
}


u32 mailbox(void)
{
    u32 send_id;
    u32 recv_id;
    mBox = msgMBoxCreate(msgMBoxPRIORITY, msgMBoxFull);
    if(NULL == mBox)
    {
        printf("msgMbox create failed\n");
        return 1;
    }
    send_id = taskSpawn("MAIL SEND", SEND_PRORITY, OPTIONS, STK_SIZE,(FUNCPTR)task_send,0,0,0,0,0,0,0,0,0,0);
    
    recv_id = taskSpawn("MAIL RECV", RECV_PRORITY, OPTIONS, STK_SIZE,(FUNCPTR)task_recv,0,0,0,0,0,0,0,0,0,0);
    printf("send task id %u\t recv task id %u\n", send_id, recv_id);
    return 0;
}


